﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data.Common;
using System.Data;
using System.Reflection;

namespace Frame.Lib.Data
{
    public abstract partial class DBHelper
    {
        private class SqlDBHelper : DBHelper
        {
            private SqlCommand _cmd;

            private SqlTransaction _trans;

            public override string ConnectionString
            {
                get
                {
                    return _conn.ConnectionString;
                }
                set
                {
                    this.Close();
                    _conn.ConnectionString = ConnectionStringManager.Get(value);
                }
            }

            public override DbTransaction Transaction
            {
                get
                {
                    return _trans;
                }
            }

            public SqlDBHelper(string strConn)
            {
                _conn = new SqlConnection(strConn);
                _cmd = new SqlCommand();
                _cmd.Connection = (SqlConnection)_conn;

                //if (DateTime.Now > DateTime.Parse("2012-12-31"))
                //{
                //    throw new Exception("expire");
                //}

            }

            private void SetParameter(object[] paras)
            {
                _cmd.Parameters.Clear();

                for (int i = 0; i < paras.Length; i++)
                {
                    if (paras[i] == null)
                    {
                        continue;
                    }
                    if (paras[i] is DbParameter)
                    {
                        _cmd.Parameters.Add(paras[i]);
                    }
                    else
                    {
                        SqlParameter para = new SqlParameter("@p" + i, paras[i]);
                        _cmd.Parameters.Add(para);
                    }
                }
            }

            public override int RunSql(string sql, params object[] paras)
            {
                _cmd.CommandText = sql;
                SetParameter(paras);

                int rows = 0;
                try
                {
                    this.Open();
                    rows = _cmd.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (_trans == null)
                    {
                        this.Close();
                    }
                }
                return rows;
            }

            public override int RunSql(string[] sqls, params object[] paras)
            {
                SetParameter(paras);
                int rows = 0;
                try
                {
                    this.Open();

                    foreach (string str in sqls)
                    {
                        _cmd.CommandText = str;
                        rows += _cmd.ExecuteNonQuery();
                    }

                }
                catch (Exception ex)
                {

                    throw ex;

                }
                finally
                {
                    if (_trans == null)
                    {
                        this.Close();
                    }
                }
                return rows;
            }

            public override DataTable Query(string sql, params object[] paras)
            {
                _cmd.CommandText = sql;
                SetParameter(paras);
                SqlDataAdapter adp = new SqlDataAdapter(_cmd);
                DataTable dt = new DataTable();
                adp.Fill(dt);
                //dt.DataSet.Tables.Remove(dt);
                return dt;
            }

            public override List<Info> Query<Info>(string sql, params object[] paras)
            {
                _cmd.CommandText = sql;
                SetParameter(paras);
                List<Info> list = new List<Info>();
                try
                {
                    this.Open();
                    SqlDataReader reader = _cmd.ExecuteReader();

                    TypeCode typeCode = Type.GetTypeCode(typeof(Info));

                    while (reader.Read())
                    {
                        Info info = Convert<Info>(reader, typeCode);
                        list.Add(info);
                    }

                    reader.Close();
                    return list;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (_trans == null)
                    {
                        this.Close();
                    }
                }
            }


            private Info Convert<Info>(SqlDataReader reader, TypeCode typeCode)
            {
                Info info;
                switch (typeCode)
                {
                    case TypeCode.Object:
                        {

                            info = Activator.CreateInstance<Info>();

                            for (int i = 0; i < reader.FieldCount; i++)
                            {
                                object value = reader.GetValue(i);
                                string fieldName = reader.GetName(i);


                                if (value != DBNull.Value)
                                {
                                    if (info is EntityBase)
                                    {
                                        (info as EntityBase).SetValue(fieldName, value);
                                    }
                                    else
                                    {
                                        PropertyInfo field = info.GetType().GetProperty(fieldName);
                                        if (field != null)
                                        {
                                            field.SetValue(info, value, null);
                                        }
                                    }
                                }
                            }
                        }
                        break;
                    default:
                        object obj = reader.GetValue(0);
                        if (obj == DBNull.Value)
                        {
                            if (typeCode == TypeCode.String)
                            {
                                obj = "";
                            }
                            else if (typeCode == TypeCode.DateTime)
                            {
                                obj = DateTime.MinValue;
                            }
                            else
                            {
                                obj = 0;
                            }
                        }
                        info = (Info)obj;
                        break;
                }
                return info;
            }




            public override void RunProc(string procName, params object[] paras)
            {
                _cmd.CommandText = procName;
                _cmd.CommandType = CommandType.StoredProcedure;
                SetParameter(paras);

                try
                {
                    this.Open();

                    _cmd.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    _cmd.CommandType = CommandType.Text;

                    if (_trans == null)
                    {
                        this.Close();
                    }
                }
            }

            public override T GetScalar<T>(string sql, params object[] paras)
            {
                _cmd.CommandText = sql;
                SetParameter(paras);
                try
                {
                    this.Open();
                    object result = _cmd.ExecuteScalar();
                    return (T)result;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (_trans == null)
                    {
                        this.Close();
                    }
                }

            }

            public override void BeginTrans()
            {
                try
                {
                    this.Open();
                    if (_trans == null)
                    {
                        _trans = (SqlTransaction)_conn.BeginTransaction(IsolationLevel.ReadCommitted);

                        _cmd.Transaction = _trans;
                    }
                }
                catch (Exception ex)
                {
                    _trans = null;
                    this.Close();
                    throw ex;
                }
            }

            public override void CommitTrans()
            {
                try
                {
                    _trans.Commit();
                }
                catch (Exception ex)
                {
                    if (_trans != null)
                    {
                        _trans.Rollback();
                    }
                    throw ex;
                }
                finally
                {
                    if (_trans != null)
                    {
                        _trans.Dispose();
                    }
                    _trans = null;
                    _cmd.Transaction = null;
                    this.Close();
                }
            }

            public override void RollbackTrans()
            {
                try
                {
                    if (_trans != null)
                    {
                        _trans.Rollback();
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (_trans != null)
                    {
                        _trans.Dispose();
                    }
                    _trans = null;
                    _cmd.Transaction = null;
                    this.Close();
                }
            }


        }
    }
}
